<?php

require_once 'Abstract.php';

class LayeredContent_Handler_Url extends LayeredContent_Handler_Abstract
{
	public $listURLs = array();
	public $resourceURLs = array();
	protected $protocol;
	protected $domain;
	protected $path;
	protected $extension;
	
	/**
	 * The action for this page. Should be list, view, create, update, or delete
	 * 
	 * @var string
	 */
	public $action = 'view';
	
	/**
	 * The default name for the homepage of the site. This page can be accessed
	 * either implicitly via http://www.mysite.com/ or explicitly via
	 * http://www.mysite.com/index.
	 * 
	 * @var string
	 */
	public $homepage = 'index';
	
	/**
	 * The default extension for html files in this website. This is the
	 * extension that will appear at the end of each file name. Usually it is
	 * 'html' or '' (no extension).
	 * 
	 * @var string
	 */
	public $defaultExtension = '';
	
	/**
	 * The default subdomain for this website. This is the subdomain that should
	 * appear when accessing the root of the site. Usually it is 'www' or ''
	 * (no subdomain).
	 * 
	 * @var string
	 */
	public $defaultSubdomain = 'www';
	
	/**
	 * Some frameworks remove everything from the $_GET global variable (e.g.
	 * CodeIgniter) and so we need to handle these ourselves.
	 * 
	 * @var array
	 */
	public $GET;
	
	/**
	 * Since we're handling GET ourselves, we'll be consistent and access the
	 * others the same way, though we're not changing them.
	 * 
	 * @var array
	 */
	public $POST;
	
	/**
	 * Since we're handling GET ourselves, we'll be consistent and access the
	 * others the same way, though we're not changing them.
	 * 
	 * @var array
	 */
	public $SERVER;
	
	
	public function init()
	{
		$this->defaultExtension = $this->config->defaultExtension;
		$this->defaultSubdomain = $this->config->defaultSubdomain;
//		$this->initResourceURLs();
		$this->initURL();
		$this->initAction();
	}
	
	/**
	 * Set a different URL than the current to simulate a different page.
	 *
	 * @param string $url The format should be /my/url, mydomain.com/my/url, or
	 * http://mydomain.com/my/url
	 */
	public function setURL($url)
	{
		list(
			$this->protocol,
			$this->domain,
			$this->path,
			$this->extension
				) = $this->parseURL($url);
	}
	
	/**
	 * Returns the url $url or the currently set URL Layered Content is using.
	 * If none has been set then it will be the current URL in the browser.
	 * 
	 * @param string An optional URL which will be parsed and returned as a full
	 * URL. If none is passed in the default is to return the currently set URL.
	 * @return string The full URL (e.g. http://mydomain.com/my/url)
	 */
	public function getURL($url = null)
	{
		$protocol = $this->protocol;
		$domain = $this->domain;
		$path = $this->path;
		$extension = $this->defaultExtension;
		
		if ($url != null) {
			list ($protocol, $domain, $path, $extension) = $this->parseURL($url);
		}
		
		// only add www on if we're not a subdomain and if the original request
		// had it
		$default = strpos($domain, '.') !== false ? '' : $this->defaultSubdomain;
		
		return "$protocol://{$default}$domain/$path$extension";
	}
	
	/**
	 * The domain of the current URL
	 *
	 * @return string
	 */
	public function getDomain()
	{
		return $this->domain;
	}
	
	/**
	 * The path after the domain. This does NOT start with a forward slash "/"
	 * though when used as a URL it should be added.
	 *
	 * @return string
	 */
	public function getPath()
	{
		return $this->path;
	}
	
	/**
	 * Returns the current extension
	 * 
	 * @return string
	 */
	public function getExtension()
	{
		return $this->extension;
	}
	
	public function getMimeType()
	{
		$ext = ($this->extension == $this->defaultExtension)
			? 'html'
			: $this->extension;
		
		$mime = $this->config->mime->$ext;
		
		if (!$mime)
			$mime = $this->config->mimes->html;
		
		return $mime;
	}
	
	/**
	 * The path along with the domain. This is used for looking up pages within
	 * the system. If desired, it will return the path with the homepage name
	 * instead of leaving it blank. Also if desired will add the extension on.
	 * 
	 * @param boolean $useHomepage If true, will use the homepage name if
	 * appropriate
	 * @param boolean $addExtension Will add the extension onto the full path if
	 * true. This will add the 'html' extension if the defaultExtension is
	 * present. Note that the extension will NOT be added to the domain if the
	 * path is the homepage and $useHomepage is false.
	 * @return string The full path for looking up pages in the system
	 */
	public function getFullPath($useHomepage = false, $addExtension = false)
	{
		$domain = $this->getDomain();
		$path = $this->getPath();
		$extension = '';
		
		if (!$path && $useHomepage)
			$path = $this->homepage;
		
		if ($addExtension) {
			$extension = $this->getExtension();
			if ($extension == $this->defaultExtension)
				$extension = '.html';
		}
		
		return $path ? "$domain/$path$extension" : $domain;
	}
	
	/**
	 * Initialize the URL to the current url from the browser.
	 */
	protected function initURL()
	{
		// does the same thing $_GET does for us, but bypasses the global $_GET
		// this fixes a bug with CodeIgniter which clears the $_GET array
		parse_str($this->SERVER['QUERY_STRING'], $this->GET);
		$this->POST = $_POST;
		$this->SERVER = $_SERVER;
		
		$this->protocol = isset($this->SERVER['HTTPS']) ? 'https' : 'http';
		$this->domain = preg_replace(
			'/^' . $this->defaultSubdomain . '\./',
			'',
			$this->SERVER['HTTP_HOST']
		);
		
		$this->domain = $this->getDomainAlias($this->domain);
		
		// remove the starting / and trailing .html or ?queryParams
		$path = preg_replace(
			'~^/|/?(\?.*)?$~',
			'',
			$this->SERVER['REQUEST_URI']
		);
		
		list($this->path, $this->extension) = explode('.', $path);
		
		if ($this->path == $this->homepage)
			$this->path = '';
		
		if (!$this->extension)
			$this->extension = $this->defaultExtension;
	}
	
	/**
	 * Initialize the action using the request method but allowing for overrides.
	 * The action could be view, create, update, or delete.
	 */
	protected function initAction()
	{
		
		
		// change action if the HTTP method is used to specify the action 
		$method = $this->SERVER['REQUEST_METHOD'];
		if ($method == 'POST')
			$this->action = 'create';
		elseif ($method == 'PUT')
			$this->action = 'update';
		elseif ($method == 'DELETE')
			$this->action = 'delete';
		
		// finally, change the action if it is set explicitly (creates, updates,
		// and deletes must always use a POST)
		if (isset($this->GET['action']))
			$actionOverride = strtolower($_GET['action']);
		elseif (isset($this->POST['action']))
			$actionOverride = strtolower($this->POST['action']);
		
		if ($actionOverride && $method == 'POST') {
			if (	$actionOverride == 'create' ||
					$actionOverride == 'update' ||
					$actionOverride == 'delete')
				$this->action = $actionOverride;
		}
	}
	
	/**
	 * Parse a URL given into its parts: protocol (e.g. http), domain (e.g.
	 * mydomain.com), and path (e.g. some/page).
	 *
	 * @param string $url A valid URL or seudo (e.g. /my/url,
	 * mydomain.com/my/url, or http://mydomain.com/my/url)
	 * @return array An array with protocol, domain, path as its members.
	 */
	protected function parseURL($url)
	{
		$protocol = $this->protocol;
		$domain = $this->domain;
		$path = $this->path;
		$extension = $this->defaultExtension;
		
		$protocolRX = '(\w+)://';
		$domainRX = '([^/]+)';
		$pathRX = '/(.*?)';
		$extRX = '(\.\w{2,4})?';
		
		$matches = array();
		if ($url[0] == '/') {
			preg_match('~^' . $pathRX . $extRX . '$~', $url, $matches);
			$path = $matches[1];
			$extension = $matches[2];
		} elseif (strpos($url, '://') !== false) {
			preg_match('~^' . $protocolRX . $domainRX . $pathRX . $extRX . '$~', $url, $matches);
			$protocol = $matches[1];
			$domain = $matches[2];
			$path = $matches[3];
			$extension = $matches[4];
		} else {
			preg_match('~^' . $domainRX . $pathRX . $extRX . '$~', $url, $matches);
			$domain = $matches[1];
			$path = $matches[2];
			$extension = $matches[3];
		}
		
		$domain = $this->getDomainAlias($domain);
		
		return array($protocol, $domain, $path, $extension);
	}
	
	
	protected function getDomainAlias($domain)
	{
		$alias = $this->config->aliases;
		foreach (explode('.', $domain) as $part) {
			if (!isset($alias->$part)) {
				return $domain;
			}
			$alias = $alias->$part;
		}
		
		if (is_string($alias)) {
			return $alias;
		}
		
		return $domain;
	}
	
	
	protected function initResourceURLs()
	{
		$types = array_reverse($this->config->resources->toArray(), true);
		
		// do several passes until we've parsed everything down to full URL
		// expressions. The reason we need to do this is that some URLs
		// reference other URLs as a starting point.
		
		$unparsedURLs = $this->getUnparsedResourceURLs($types);
		
		foreach ($unparsedURLs as $urlInfo) {
			$this->parseResourceURL($urlInfo);
		}
	}
	
	protected function getUnparsedResourceURLs($types)
	{
		$unparsedURLs = array();
		
		foreach ($types as $class => $type) {
			
			// create the explicit list array
			$lists = array();
			if (isset($type['urls']['list'])) {
				if (is_array($type['urls']['list']))
					$lists = array_merge($lists, $type['urls']['list']);
				else
					$lists[] = $type['urls']['list'];
			}
			
			// create the resource URL array
			$urls = array();
			if (is_array($type['urls']['resource']))
				$urls = array_merge($urls, $type['urls']['resource']);
			else
				$urls[] = $type['urls']['resource'];
			
			// add implicit list URLs
			foreach ($urls as $url) {
				$matches = null;
				if (preg_match('~^(.*/[^/]+)/:~', $url, $matches))
					$lists[] = $matches[1];
			}
			
			foreach ($lists as $url)
				$unparsedURLs[] = array($url, $class, 'list');
			
			foreach ($urls as $url)
				$unparsedURLs[] = array($url, $class, 'resource');
		}
		
		return $unparsedURLs;
	}
	
	protected function parseResourceURL($urlInfo)
	{
		list($url, $class, $type) = $urlInfo;
		
		
	}
}

